﻿using TripleGame.Core;
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;

namespace TripleGame.NaiveEngine
{

    public class MinkovTodorovEngine : ITripleGameEngine
    {
        private class Move
            : IComparable<Move>
        {
            public int startX, startY, endX, endY;
            public int income;
            public int screw;
            public int randomId;
            public static int remainingCells = 0;

            public int CompareTo(Move other)
            {
                //if (this.income == 3) return (5).CompareTo(0);
                //else if (other.income == 3) return (0).CompareTo(5);
                if ((this.screw + (this.income / 3.0) * 10 * (remainingCells / 50.0)).CompareTo(other.screw + (other.income / 3.0) * 10 * (remainingCells / 50.0)) == 0)
                {
                    return this.randomId.CompareTo(other.randomId);
                }
                return (this.screw + (this.income / 3.0) * 10 * (remainingCells / 50.0)).CompareTo(other.screw + (other.income / 3.0) * 10 * (remainingCells / 50.0));
                //if (this.screw == other.screw)
                //{
                //    if (this.income == other.income)
                //    {
                //        return this.randomId.CompareTo(other.randomId);
                //    }
                //    return this.income.CompareTo(other.income);
                //}
                //else
                //{
                //    return screw.CompareTo(other.screw);
                //}
                //if (this.income == other.income)
                //{
                //    return this.screw.CompareTo(other.screw);
                //}
                //else
                //{
                //    return this.income.CompareTo(other.income);
                //}
            }
            public override string ToString()
            {
                return startX + "," + startY + "-" + endX + "," + endY + " has income " + income + " and screw " + screw;
            }
        }
        public static Random rand = new Random();
        private const char EMPTY_CELL = ' ';

        public string EngineName
        {
            get { return "Minkov&Todorov engine"; }
        }

        public void PerformMove(char[,] board, char playerLetter,
            out int startX, out int startY, out int endX, out int endY)
        {
            Move.remainingCells = 0;

            List<Move> moves = InspectValidMoves(board, playerLetter);

            for (int i = 0; i < moves.Count; i++)
            {


                moves[i].income = CountIncome(moves[i], board, playerLetter);

                moves[i].screw = CountScrewed(moves[i], board, playerLetter);
            }

            if (moves.Count > 0)
            {
                moves.Sort();

        
                int index = moves.Count - 1;
                startY = moves[index].startX;
                startX = moves[index].startY;
                endY = moves[index].endX;
                endX = moves[index].endY;
                //  MessageBox.Show("("+startX + "," + startY +")  (" + endX + "," + endY+")");
            }
            else
            {
                throw new InvalidOperationException("No valid moves were found.");
            }
        }

        private int CountScrewed(Move move, char[,] board, char playerLetter)
        {
            int screwed = 0;
            char opponentLetter = (Char.ToUpperInvariant(playerLetter) == 'A') ? 'B' : 'A';

            List<Move> opponentMoves = InspectValidMoves(board, opponentLetter);
            for (int i = 0; i < opponentMoves.Count; i++)
            {
                int x = opponentMoves[i].startX;
                int y = opponentMoves[i].startY;
                int dx = (opponentMoves[i].endX - opponentMoves[i].startX) / 2;
                int dy = (opponentMoves[i].endY - opponentMoves[i].startY) / 2;
                bool willFail = false;

                int toScrew = 3;
                for (int cell = 0; cell < 3; cell++)
                {
                    if (char.ToUpperInvariant(board[x, y]) != char.ToUpperInvariant(EMPTY_CELL)) toScrew--;
                    int x1 = move.startX;
                    int y1 = move.startY;
                    int dx1 = (move.endX - move.startX) / 2;
                    int dy1 = (move.endY - move.startY) / 2;

                    for (int cell1 = 0; cell1 < 3; cell1++)
                    {
                        if (x == x1 && y == y1)
                        {
                            willFail = true;
                        }
                        x1 += dx1;
                        y1 += dy1;
                    }

                    x += dx;
                    y += dy;
                }
                if (willFail)
                {
                    screwed += toScrew;
                }
            }

            return screwed;
        }

        private int CountIncome(Move move, char[,] board, char playerLetter)
        {
            int income = 0;
            int x = move.startX;
            int y = move.startY;
            int dx = (move.endX - move.startX) / 2;
            int dy = (move.endY - move.startY) / 2;
      //      sw.WriteLine(x + "," + y + " " + dx + "," + dy);
            for (int i = 0; i < 3; i++)
            {
             //   sw.Write(Char.ToUpperInvariant(board[x, y]) + "," + Char.ToUpperInvariant(playerLetter) + " ");
                if (Char.ToUpperInvariant(board[x, y]) != Char.ToUpperInvariant(playerLetter))
                    income++;
                x += dx;
                y += dy;
            }
        //    sw.WriteLine(income.ToString());

            return income;
        }

        private List<Move> InspectValidMoves(char[,] board, char playerLetter)
        {


            List<Move> result = new List<Move>();
            for (int i = 0; i < board.GetLength(0); i++)
            {
                for (int j = 0; j < board.GetLength(1); j++)
                {
                    if (char.ToUpperInvariant(board[i, j]) == char.ToUpperInvariant(EMPTY_CELL))
                    {
                        Move.remainingCells++;
                    }
                    if (IsMoveValid(board, playerLetter, i, j, 1, 0))
                    {
                        result.Add(new Move() { startX = i, startY = j, endX = i + 2, endY = j, randomId = rand.Next() });
                    }
                    if (IsMoveValid(board, playerLetter, i, j, 1, 1))
                    {
                        result.Add(new Move() { startX = i, startY = j, endX = i + 2, endY = j + 2, randomId = rand.Next() });
                    }
                    if (IsMoveValid(board, playerLetter, i, j, 0, 1))
                    {
                        result.Add(new Move() { startX = i, startY = j, endX = i, endY = j + 2, randomId = rand.Next() });
                    }
                    if (IsMoveValid(board, playerLetter, i, j, 1, -1))
                    {
                        result.Add(new Move() { startX = i, startY = j, endX = i + 2, endY = j - 2, randomId = rand.Next() });
                    }
                }
            }

            return result;

        }


        private bool IsMoveValid(char[,] board, char playerLetter,
            int startRow, int startCol, int stepX, int stepY)
        {
            int row = startRow;
            int col = startCol;
            int numberOfEmptyCellsFilled = 0;
            for (int i = 1; i <= 3; i++)
            {
                if (row < 0 || row >= board.GetLength(0) ||
                    col < 0 || col >= board.GetLength(1))
                {
                    return false;
                }

                char currentCellUpcase = Char.ToUpperInvariant(board[row, col]);
                char playerLetterUpcase = Char.ToUpperInvariant(playerLetter);
                if (currentCellUpcase == EMPTY_CELL)
                {
                    numberOfEmptyCellsFilled++;
                }
                else if (currentCellUpcase != playerLetterUpcase)
                {
                    return false;
                }
                row += stepX;
                col += stepY;
            }

            if (numberOfEmptyCellsFilled == 0)
            {
                return false;
            }

            return true;
        }

    }
}
